import json
from time import sleep, time
from pickle import dump, load
from os.path import exists
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

class Concert(object):
    def __init__(self, config_path='./config.json'):
        with open(config_path, 'r', encoding='utf-8') as f:
            config = json.load(f)
        self.date = config['date']
        self.session = config['sess']
        self.price = config['price']
        self.real_name = config['real_name']
        self.nick_name = config['nick_name']
        self.ticket_num = config['ticket_num']
        self.damai_url = config['damai_url']
        self.target_url = config['target_url']
        self.driver_path = config['driver_path']
        self.driver = None
        self.status = 0
        self.time_start = 0
        self.time_end = 0
        self.num = 0
        self.setup_driver()  # 初始化浏览器驱动

    def setup_driver(self):
        """设置WebDriver，并预加载cookies，如果存在的话。"""
        options = webdriver.EdgeOptions()
        prefs = {
            "profile.managed_default_content_settings.images": 2,
            "profile.managed_default_content_settings.javascript": 1,
            'permissions.default.stylesheet': 2
        }
        options.add_experimental_option("prefs", prefs)
        capa = DesiredCapabilities.EDGE
        capa["pageLoadStrategy"] = "none"
        self.driver = webdriver.Edge( options=options)
        
        if exists('cookies.pkl'):
            self.driver.get(self.damai_url)  # 需要先访问网站才能设置cookies
            cookies = load(open("cookies.pkl", "rb"))
            for cookie in cookies:
                if 'expiry' in cookie:
                    del cookie['expiry']
                self.driver.add_cookie(cookie)
            print(u'Cookie载入完成')
        else:
            print(u"Cookie未找到，请先运行get_cookie方法获取")

    def get_cookie(self):
        """获取并保存登录cookie。"""
        self.driver.get(self.damai_url)
        print(u"###请点击登录###")
        input("请在登录完成后按任意键继续...")
        dump(self.driver.get_cookies(), open("cookies.pkl", "wb"))
        print(u"###Cookie保存成功###")
        self.driver.quit()

    def enter_concert(self):
        """进入指定的抢票页面。"""
        self.driver.get(self.target_url)
        WebDriverWait(self.driver, 10, 0.1).until(EC.title_contains('大麦网'))
        print(u'成功进入目标页面')

    def choose_ticket(self):
        print(u"###进入抢票界面###")
        while self.driver.title.find('确认订单') == -1:  # 如果跳转到了确认界面就算这步成功了，否则继续执行此步
            self.num += 1  #尝试次数加1

            if con.driver.current_url.find("buy.damai.cn") != -1:
                break

            # 确认页面刷新成功
            try:
                box = WebDriverWait(self.driver, 1, 0.1).until(EC.presence_of_element_located((By.CLASS_NAME, 'perform__order__box')))
            except:
                raise Exception(u"***Error: 页面刷新出错***")

            try:
                realname_popup = box.find_elements_by_xpath("//div[@class='realname-popup']")  # 寻找实名身份遮罩
                if len(realname_popup) != 0:
                    known_button = realname_popup[0].find_elements_by_xpath("//div[@class='operate']//div[@class='button']")
                    known_button[0].click()
            except:
                raise Exception(u"***Error: 实名制遮罩关闭失败***")

            try:
                buybutton = box.find_element_by_class_name('buybtn') # 寻找立即购买标签
                buybutton_text = buybutton.text
            except:
                raise Exception(u"***Error: buybutton 位置找不到***")

            if buybutton_text == "即将开抢" or buybutton_text == "即将开售":
                self.status = 2
                raise Exception(u"---尚未开售，刷新等待---")

            try:
                selects = box.find_elements_by_class_name('perform__order__select') # 日期、场次和票档进行定位
                date = None  # 有的演出没有日期的选项
                for item in selects:
                    if item.find_element_by_class_name('select_left').text == '日期':
                        date = item
                        # print('\t日期定位成功')
                    elif item.find_element_by_class_name('select_left').text == '场次':
                        session = item
                        # print('\t场次定位成功')
                    elif item.find_element_by_class_name('select_left').text == '票档':
                        price = item
                        # print('\t票档定位成功')

                if date is not None:
                    date_list = date.find_elements_by_xpath("//div[@class='wh_content_item']//div[starts-with(@class,'wh_item_date')]") #选定日期
                    # print('可选日期数量为：{}'.format(len(date_list)))
                    for i in self.date:
                        j = date_list[i-1]
                        j.click()
                        break

                session_list = session.find_elements_by_class_name('select_right_list_item')#选定场次
                # print('可选场次数量为：{}'.format(len(session_list)))
                for i in self.session:  # 根据优先级选择一个可行场次
                    j = session_list[i-1]
                    k = self.isClassPresent(j, 'presell', True)
                    if k: # 如果找到了带presell的类
                        if k.text == '无票':
                            continue
                        elif k.text == '预售':
                            j.click()
                            break
                        elif k.text == '惠':
                            j.click()
                            break
                    else:
                        j.click()# 选定好场次点击按钮确定
                        break

                price_list = price.find_elements_by_class_name('select_right_list_item')#选定票档
                # print('可选票档数量为：{}'.format(len(price_list)))
                for i in self.price:
                    j = price_list[i-1]
                    k = self.isClassPresent(j, 'notticket')
                    if k:  # 存在notticket代表存在缺货登记，跳过
                        continue
                    else:
                        j.click()#选定好票档点击确定
                        break
            except:
                raise Exception(u"***Error: 选择日期or场次or票档不成功***")

            try:
                ticket_num_up = box.find_element_by_class_name('cafe-c-input-number-handler-up')
            except:
                if buybutton_text == "选座购买":  # 选座购买没有增减票数键
                    buybutton.click()
                    self.status = 5
                    print(u"###请自行选择位置和票价###")
                    break
                elif buybutton_text == "提交缺货登记":
                    raise Exception(u'###票已被抢完，持续捡漏中...或请关闭程序并手动提交缺货登记###')
                else:
                    raise Exception(u"***Error: ticket_num_up 位置找不到***")

            if buybutton_text == "立即预订":
                for i in range(self.ticket_num-1):  # 设置增加票数
                    ticket_num_up.click()
                buybutton.click()
                self.status = 3

            elif buybutton_text == "立即购买":
                for i in range(self.ticket_num-1):  # 设置增加票数
                    ticket_num_up.click()
                buybutton.click()
                self.status = 4

    def check_order(self):
        if self.status in [3, 4, 5]:
            if self.real_name is not None:
                print(u"###等待--确认订单--页面出现，可自行刷新，若长期不跳转可选择-- CRTL+C --重新抢票###")
                try:
                    tb = WebDriverWait(self.driver, 1, 0.1).until(EC.presence_of_element_located((By.XPATH, '/html/body/div[3]/div[2]/div')))
                except:
                    raise Exception(u"***Error：实名信息选择框没有显示***")

                print(u'###开始确认订单###')
                print(u'###选择购票人信息,可手动帮助点击###')
                init_sleeptime = 0.0
                Labels = tb.find_elements_by_tag_name('label')

                # 防止点击过快导致没有选择多个人
                while True:
                    init_sleeptime += 0.1
                    true_num = 0
                    for num_people in self.real_name:
                        tag_input = Labels[num_people-1].find_element_by_tag_name('input')
                        if tag_input.get_attribute('aria-checked') == 'false':
                            sleep(init_sleeptime)
                            tag_input.click()
                        else:
                            true_num += 1
                    if true_num == len(self.real_name):
                        break
                print("本次抢票时间：", time()-self.time_start)
                self.driver.find_element_by_xpath('/html/body/div[3]/div[2]/div/div[9]/button').click() # 同意以上协议并提交订单

            else:
                self.driver.find_element_by_xpath('/html/body/div[2]/div[2]/div/div[8]/button').click()

            # 判断title是不是支付宝
            print(u"###等待跳转到--付款界面--，可自行刷新，若长期不跳转可选择-- CRTL+C --重新抢票###")
            try:
                WebDriverWait(self.driver, 3600, 0.1).until(EC.title_contains('支付宝'))
            except:
                raise Exception(u'***Error: 长期跳转不到付款界面***')

            self.status = 6
            print(u'###成功提交订单,请手动支付###')
            self.time_end = time()
    def start(self):
        self.enter_concert()
        while True:
            try:
                self.choose_ticket()
                self.check_order()
                if self.status == 6:
                    print(u"###经过%d轮奋斗，共耗时%.1f秒，抢票成功！请确认订单信息###" % (self.num, time() - self.time_start))
                    break
            except Exception as e:
                print(e)
                self.driver.refresh()
        self.driver.quit()


if __name__ == '__main__':
    concert = Concert('大麦\config.json')
    concert.start()
